import Taro from '@tarojs/taro';
import { firstValueFrom } from 'rxjs';

import * as VodUploader from "vod-wx-sdk-v2";
import CosAuth from '@/libs/cos-auth';
import CONFIG from '@/config';
import { rxRequest } from './rxHelpers';

//本方法不需要导入cos sdk，为简化版本，不是最安全版本
// 请求用到的参数
// const prefix = 'https://cos.' + config.Region + '.myqcloud.com/' + config.Bucket + '/'; // 这个是后缀式，签名也要指定 Pathname: '/' + config.Bucket + '/'
const prefix = 'https://' + CONFIG.COS_CONF.BUCKET + '.cos.' + CONFIG.COS_CONF.REGION + '.myqcloud.com/';

// 对更多字符编码的 url encode 格式
const camSafeUrlEncode = (str: string) => {
  return encodeURIComponent(str)
    .replace(/!/g, '%21')
    .replace(/'/g, '%27')
    .replace(/\(/g, '%28')
    .replace(/\)/g, '%29')
    .replace(/\*/g, '%2A');
};

type StsCacheType = {
  expiredTime: number;
  credentials: string;
}
// 获取临时密钥
let stsCache: StsCacheType;

const getCredentials = (callback: any) => {
  if (stsCache && Date.now() / 1000 + 30 < stsCache.expiredTime) {
    callback(stsCache.credentials);
    return;
  }

  const costAuth$ = rxRequest<StsCacheType>({
    url: CONFIG.BASE_URL + "/v1/live/QCloud/cosAuth",
    withJwt: true
  })

  firstValueFrom(costAuth$)
    .then(data => {
      const credentials = data.credentials;
      if (credentials) {
        stsCache = data;
      } else {
        // Taro.showModal({ title: '临时密钥获取失败', content: JSON.stringify(data), showCancel: false });
        console.error("临时密钥获取失败");
      }
      callback(stsCache && stsCache.credentials);
    }).catch(err => {
      //Taro.showModal({ title: '临时密钥获取失败', content: JSON.stringify(err), showCancel: false });
      console.error("临时密钥获取失败", err);
    })
}

// 计算签名
const getAuthorization = (options: any, callback: any) => {
  getCredentials(function (credentials: { sessionToken: string; tmpSecretId: string; tmpSecretKey: string; }) {
    callback({
      XCosSecurityToken: credentials.sessionToken,
      Authorization: CosAuth({
        SecretId: credentials.tmpSecretId,
        SecretKey: credentials.tmpSecretKey,
        Method: options.Method,
        Pathname: options.Pathname,
      })
    });
  });
};

// 上传文件
const uploadFile = (filePath: string, success?: any, fail?: any) => {
  const Key = filePath.substr(filePath.lastIndexOf('/') + 1); // 这里指定上传的文件名
  getAuthorization({ Method: 'POST', Pathname: '/' }, async function (AuthData: { Authorization: string; XCosSecurityToken: string; }) {
    const requestTask = await Taro.uploadFile({
      url: prefix,
      name: 'file',
      filePath: filePath,
      formData: {
        'key': Key,
        'success_action_status': 200,
        'Signature': AuthData.Authorization,
        'x-cos-security-token': AuthData.XCosSecurityToken,
        'Content-Type': '',
      },
      success: function (res) {
        console.log('腾讯云上传成功的返回值：', res)
        const url = prefix + camSafeUrlEncode(Key).replace(/%2F/g, '/');
        if (res.statusCode === 200) {
          const cdnUrl = url.replace(/cos.ap-guangzhou/g, "file");
          success && success(cdnUrl);
        } else {
          console.error("上传失败: ", res);
          fail && fail(res);
        }
      },
      fail: function (err) {
        fail && fail(err);
      }
    })

    requestTask.onProgressUpdate = (res) => {
      console.log('正在进度: ', res);
    }
  });
}

//获取签名
const getVodSign = (callback: any) => {
  const vodSign$ = rxRequest({
    url: CONFIG.BASE_URL + "/v1/live/QCloud/vodAuth",
    withJwt: true
  })
  firstValueFrom(vodSign$)
    .then(callback)
    .catch(error => {
      console.error("获取vod签名失败: ", error);
    })
};

type FileInfo = {
  // mediaFile: Taro.chooseVideo.SuccessCallbackResult;
  // mediaFile: Taro.chooseMedia.SuccessCallbackResult;
  mediaFile: Taro.chooseMedia.ChooseMedia;
  coverFile: Taro.chooseImage.SuccessCallbackResult;
  mediaName?: string;
}

const vodUploader = (info: FileInfo, success?: any, fail?: any, progress?: any) => {
  const uploader = VodUploader.start({
    mediaFile: info.mediaFile, //必填，把chooseVideo回调的参数(file)传进来
    getSignature: getVodSign, //必填，获取签名的函数
    mediaName: info.mediaName ? info.mediaName : null, //选填，视频名称，强烈推荐填写(如果不填，则默认为“来自小程序”)
    // coverFile: info.coverFile, // 选填，视频封面
    error: !fail ? () => { return } : fail,
    progress: !progress ? () => { return } : progress,
    finish: !success ? () => { return } : success,
  })
  return uploader;
}

type WxaCodeResult = {
  buffer: ArrayBuffer;
  contentType: string;
  errCode: number;
  errMsg: string;
}

//TODO 生成直播间的小程序码并存起来，需要加入推荐来源。注意scene的长度只有32位
const getWxaCode = (roomId: string, refId?: string, page?: string, width?: number) => {
  return new Promise(function (resolve, reject) {
    const wxaCodes = Taro.getStorageSync('wxaCodes') || [];
    const thisCode = wxaCodes.filter(item => item.roomId === roomId);
    if (thisCode.length > 0) resolve(thisCode[0].code);
    const w = !width || width < 280 ? '280' : width.toString();

    // const scene = 'refId$' + refId;

    const scene = refId;
    Taro.cloud.callFunction({
      name: 'getWxaCode',
      data: {
        page,
        scene,
        width: w,
      },
      success: res => {
        const wxaRes = res.result as WxaCodeResult;

        if (wxaRes && wxaRes.errCode === 0) {
          const code = Taro.arrayBufferToBase64(wxaRes.buffer);

          if (wxaCodes.length >= 5) {
            wxaCodes.shift()
          }
          const curCode = {
            roomId,
            code
          }
          wxaCodes.push(curCode);
          Taro.setStorageSync('wxaCodes', wxaCodes);

          resolve(code);
        } else {
          reject(res.errMsg);
        }
      },
      fail: err => {
        reject(err.errMsg);
      }
    })
  })
}

// 实现消息订阅
const subscribeMessage = (theme: string, roomName: string, nickName: string, startTime: string, desc: string) => {
  return new Promise(function (resolve, reject) {
    Taro.cloud.callFunction({
      name: 'subscribeMessage',
      data: {
        theme,
        roomName,
        nickName,
        startTime,
        desc
      },
      success: res => {
        console.log('云函数调用成功', res);
      },
      fail: err => {
        console.log('云函数调用失败', err);
      }
    })
  })
}

export {
  uploadFile,
  vodUploader,
  getWxaCode,
  subscribeMessage,
}

export default {
  uploadFile,
  vodUploader,
  getWxaCode,
  subscribeMessage,
}